package org.fing.edu.uy.esbadp.core.registry;

import java.util.logging.Level;

import org.fing.edu.uy.esbadp.core.constants.EsbAdpPropertyConstants;
import org.fing.edu.uy.esbadp.core.entity.DMAdpConfigProperties;
import org.fing.edu.uy.esbadp.core.entity.DMAdpConfigProperty;
import org.fing.edu.uy.esbadp.core.entity.DMAdpMonitorMechanism;
import org.fing.edu.uy.esbadp.core.entity.DMAdpMonitorMechanisms;
import org.fing.edu.uy.esbadp.core.entity.DMAdpMonitorProperties;
import org.fing.edu.uy.esbadp.core.entity.DMAdpMonitorProperty;
import org.fing.edu.uy.esbadp.core.entity.DMAdpServiceRequirement;
import org.fing.edu.uy.esbadp.core.entity.DMAdpServiceRequirements;
import org.fing.edu.uy.esbadp.core.entity.DMAdpServices;
import org.fing.edu.uy.esbadp.core.interfaces.IAdpProperties;
import org.fing.edu.uy.esbadp.core.interfaces.IAdpServiceRequirement;
import org.fing.edu.uy.esbadp.core.interfaces.IMechanismMonitor;
import org.fing.edu.uy.esbadp.logger.LoggerADP;
import org.fing.edu.uy.esbadp.requirements.AdpRequirementSimpleCondition;

@SuppressWarnings("rawtypes")
public class RegistryManager {
	
	private static java.util.logging.Logger logger = LoggerADP.getLogger(RegistryManager.class.getSimpleName());

	private static RegistryManager instance = null;
	
	/* Registro de servicios de adaptacion cargados desde los archivos de configuracion */
	private DMAdpServices adpServices;
	
	/* Registro de requerimientos de adaptacion cargados desde los archivos de configuracion */
	private DMAdpServiceRequirements adpServiceRequirements;
		
	/*Registro de los mecanismos de monitoreo cargado desde los archivos de configuracion*/
	private DMAdpMonitorMechanisms adpMonitorMechanism;
	
	/*Registro de los mecanismos de monitoreo cargado desde los archivos de configuracion*/
	private DMAdpMonitorProperties adpMonitorProperties;
	
	/*Lista de las las propiedades de configuracion*/
	private DMAdpConfigProperties adpConfigProperties;
	
	private RegistryManager (){	}
	
	public synchronized static RegistryManager getInstance(){
		if(instance==null){
			instance = new RegistryManager();
		}
		return instance;
	}

	public DMAdpServices getAdpServices() {
		return adpServices;
	}

	public void setAdpServices(DMAdpServices adpServices) {
		this.adpServices = adpServices;
	}

	public DMAdpServiceRequirements getAdpServiceRequirements() {
		return adpServiceRequirements;
	}

	public void setAdpServiceRequirements(DMAdpServiceRequirements adpServiceRequirements) {
		this.adpServiceRequirements = adpServiceRequirements;
	}

	public DMAdpMonitorMechanisms getAdpMonitorMechanism() {
		return adpMonitorMechanism;
	}
	
	public void setAdpMonitorMechanism(DMAdpMonitorMechanisms adpMonitorMechanism) {
		this.adpMonitorMechanism = adpMonitorMechanism;
	}

	public DMAdpMonitorProperties getAdpMonitorProperties() {
		return adpMonitorProperties;
	}

	public void setAdpMonitorProperties(DMAdpMonitorProperties adpMonitorProperties) {
		this.adpMonitorProperties = adpMonitorProperties;
	}
	
	public DMAdpConfigProperties getAdpConfigProperties() {
		return adpConfigProperties;
	}
	
	public String getAdpConfigProperty(String key,String defaultValue) {
		String res = defaultValue;
		for(DMAdpConfigProperty aux:adpConfigProperties.getProperties()){
			if(aux.getPropertyName().equalsIgnoreCase(key)){
				res = aux.getValue();
				break;
			}
		}
		return res;		
	}

	public void setAdpConfigProperties(DMAdpConfigProperties adpConfigProperties) {
		this.adpConfigProperties = adpConfigProperties;
	}
	
	
	/**
	 * 
	 * @param valueName valor indentificador para el mecanismo registrado
	 * @return nueva intancia del mecanismo de monitoreo , null en caso de que no exista o no se pueda crear.
	 */
	public IMechanismMonitor getAdpMechanismMonitor(String valueName){
		Class klass;		
		
		//busco un mecanismo registrado que coincida con el valueName
		DMAdpMonitorMechanism auxMechanism = null;
		for(DMAdpMonitorMechanism aux:this.adpMonitorMechanism.getMechanisms()){
			if(aux.getValueName().equalsIgnoreCase(valueName)){
				auxMechanism = aux;
				break;
			}
		}
		
		//si encontre un mecanismo que coincida creo y retorno la instancia.
		if(auxMechanism != null){
			try {
				klass = Class.forName(auxMechanism.getClassName());
				IMechanismMonitor adpMonitorMechanism = (IMechanismMonitor) klass.newInstance();				
				return adpMonitorMechanism;
			} catch (Exception e) {
				logger.log(Level.SEVERE, "Error creating new instance of" + auxMechanism.getClassName(),e);
				return null;
			} 			
		}else{
			logger.log(Level.SEVERE, "The mechanism is not registered");
			return null;
		}		
	}
	
	
	/**
	 * 
	 * @param valuePropertie valor indentificador para la propiedad requerida
	 * @return nueva intancia de la clase que calcula la propiedad de monitoreo , null en caso de que no exista o no se pueda crear.
	 */
	public IAdpProperties getAdpMonitorProperty(String valuePropertie){
		Class klass;		
		
		//busco la propiedades registradas que coincida con el valueName
		DMAdpMonitorProperty auxProperty= null;
		for(DMAdpMonitorProperty aux:this.adpMonitorProperties.getProperties()){
			if(aux.getPropertyName().equalsIgnoreCase(valuePropertie)){
				auxProperty = aux;
				break;
			}
		}
		
		//si encontre un mecanismo que coincida creo y retorno la instancia.
		if(auxProperty != null){
			try {
				klass = Class.forName(auxProperty.getClassName());
				IAdpProperties adpMonitorProperty = (IAdpProperties) klass.newInstance();				
				return adpMonitorProperty;
			} catch (Exception e) {
				logger.log(Level.SEVERE, "Error creating new instance of " + auxProperty.getClassName(),e);
				return null;
			} 			
		}else{
			logger.log(Level.SEVERE, "The property is not registered");
			return null;
		}		
	}
	
	
	/**
	 * 
	 * @param requirementName valor indentificador para el requerimiento
	 * @return nueva intancia de la clase que implementa el requerimiento 
	 * 	 ** si es compleja crea una instancia nueva del requerimiento
	 *   ** si es simple crea una instancia de una clase de apoyo para la evaluacion de la condicion. 
	 */
	public IAdpServiceRequirement getAdpRequirement(String requirementName){		
		//busca la definicion del requerimiento 
		DMAdpServiceRequirement auxReq = null;
		
		for(DMAdpServiceRequirement aux : this.adpServiceRequirements.getRequirements()){
			if(aux.getName().equalsIgnoreCase(requirementName)){
				auxReq = aux;
				break;
			}
		}		
		
		Class klass;	
		//si encontre un requerimiento que coincida creo y retorno la instancia.
		if(auxReq != null){
			
			if(auxReq.getCondition().getType().equalsIgnoreCase(EsbAdpPropertyConstants.REQUIREMENTS_ELEMENT_CONDITION_TYPE_SIMPLE)){
				
			 AdpRequirementSimpleCondition req = new AdpRequirementSimpleCondition(auxReq.getCondition().getOperator(),
											  auxReq.getCondition().getServiceMeta(),
											  auxReq.getCondition().getPropName());
			 return req;
			
			}else if (auxReq.getCondition().getType().equalsIgnoreCase(EsbAdpPropertyConstants.REQUIREMENTS_ELEMENT_CONDITION_TYPE_COMPLEX)){				
				try {
					klass = Class.forName(auxReq.getCondition().getClassName());
					IAdpServiceRequirement adpRequirement = (IAdpServiceRequirement) klass.newInstance();				
					return adpRequirement;
				} catch (Exception e) {
					logger.log(Level.SEVERE, "Error creating new instance of " + auxReq.getCondition().getClassName(),e);
					return null;
				} 
			}			
						
		}else{
			logger.log(Level.SEVERE, "The requirement is not registered");
			return null;
		}
		return null;		
	}
	
}
